﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Text;

namespace DoNet.SFExpress.Framework
{
    public class HttpHelper
    {
        /// <summary>
        /// api接口 请求地址
        /// 生产环境地址 https://bspgw.sf-express.com/std/service
        /// 香港生产环境 https://sfapi-hk.sf-express.com/std/service
        /// 沙箱环境地址 https://sfapi-sbox.sf-express.com/std/service
        /// </summary>
        public static string sfapi_url = "https://{0}.sf-express.com/std/service";

        /// <summary>
        /// (SGSPDCS)api接口 请求地址
        /// 生产环境地址 https://sfapi.sf-express.com/std/service
        /// 沙箱环境地址 https://sfapi-sbox.sf-express.com/std/service 
        /// </summary>
        public static string sfapi_url_sgspdcs = "https://{0}.sf-express.com/std/service";
        
        /// <summary>
        /// accessToken 请求地址
        /// 正式环境 https://sfapi.sf-express.com/oauth2/accessToken
        /// 沙箱环境 https://sfapi-sbox.sf-express.com/oauth2/accessToken
        /// </summary>
        public static string sfapi_url_token = "https://{0}.sf-express.com/oauth2/accessToken";

        /// <summary>
        /// 箱单发票上传 请求地址
        /// </summary>
        public static string sfapi_url_fop = "https://fop.sf-express.com/restApi/ifosOrderService/fop-app-fca/order/packing/attachment/add";

        #region 图片回传接口
        /// <summary>
        /// 图片回传接口 请求地址
        /// 测试环境：http://fapi.sit.sf-express.com/hinplusService/routerPic/imageUpload
        /// </summary>
        public static string sfapi_url_fis_sit = "http://fapi.sit.sf-express.com/hinplusService/routerPic/imageUpload";
        /// <summary>
        /// 图片回传接口 请求地址
        /// 生产环境：https://fapi.sf-express.com/hinplusService/routerPic/imageUpload
        /// </summary>
        public static string sfapi_url_fis = "https://fapi.sf-express.com/hinplusService/routerPic/imageUpload";
        #endregion 图片回传接口

        /// <summary>
        /// 回传报价 接口请求地址
        /// </summary>
        public static string sfapi_url_sit = "http://fapi.sit.sf-express.com/fopApiServices/access/enter";

        /// <summary>
        /// 顺丰接口POST请求
        /// </summary>
        /// <param name="content"></param>
        /// <param name="environment">
        /// 1.api接口调用环境，bspgw：生产环境；sfapi-hk：香港生产环境；sfapi-sbox：沙箱环境
        /// 2.AccessToken调用环境，sfapi：生产环境；sfapi-sbox：沙箱环境
        /// </param>
        /// <returns></returns>
        private static string HttpPost(string url, Dictionary<string, string> content, Dictionary<string, string> header = null, string environment = "bspgw")
        {
            string result = "";
            HttpWebRequest request = null;
            try
            {
                string reqURL = string.Format(url, environment);
                request = (HttpWebRequest)WebRequest.Create(reqURL);
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";

                #region header
                if (header != null && header.Count != 0)
                {
                    foreach (var item in header)
                    {
                        request.Headers.Add(item.Key, item.Value);
                    }
                }
                #endregion

                if (!(content == null || content.Count == 0))
                {
                    StringBuilder buffer = new StringBuilder();
                    int i = 0;
                    foreach (string key in content.Keys)
                    {
                        if (i > 0)
                        {
                            buffer.Append("&");
                        }
                        buffer.AppendFormat("{0}={1}", key, content[key]);
                        i++;
                    }

                    byte[] data = Encoding.UTF8.GetBytes(buffer.ToString());
                    request.ContentLength = data.Length;
                    using (Stream reqStream = request.GetRequestStream())
                    {
                        reqStream.Write(data, 0, data.Length);
                        reqStream.Close();
                    }
                }

                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                {
                    using (Stream stream = resp.GetResponseStream())
                    {
                        //获取响应内容
                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            result = reader.ReadToEnd();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                var error = ex.ToString();
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        /// <summary>
        /// 顺丰接口POST请求（上传文件）
        /// </summary>
        /// <param name="postData"></param>
        /// <param name="fileDictionary"></param>
        /// <returns></returns>
        private static string HttpFile(string url, string postData, Dictionary<string, string> fileDictionary = null)
        {
            string result = "";
            HttpWebRequest request = null;
            try
            {
                string reqURL = url;
                request = (HttpWebRequest)WebRequest.Create(reqURL);
                request.Method = "POST";

                Encoding encoding = Encoding.UTF8; //默认编码

                #region 将参数转换成流
                MemoryStream postStream = null;
                if (!string.IsNullOrEmpty(postData))
                {
                    byte[] array = encoding.GetBytes(postData);
                    postStream = new MemoryStream(array);
                }
                #endregion

                string contentType = "";
                #region 处理Form表单文件上传
                var formUploadFile = fileDictionary != null && fileDictionary.Count > 0;//是否用Form上传文件
                if (formUploadFile)
                {
                    contentType = "multipart/form-data";

                    //通过表单上传文件
                    string boundary = "----" + DateTimeOffset.Now.Ticks.ToString("x");

                    postStream = postStream ?? new MemoryStream();
                    //byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
                    string fileFormdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
                    string dataFormdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";

                    foreach (var file in fileDictionary)
                    {
                        try
                        {
                            var fileNameOrFileData = file.Value;

                            string formdata = null;
                            using (var memoryStream = new MemoryStream())
                            {
                                //fileNameOrFileData 中储存的储存的可能是文件地址或备注
                                //准备文件流
                                using (var fileStream = FileHelper.GetFileStream(fileNameOrFileData))
                                {
                                    if (fileStream != null)
                                    {
                                        //存在文件
                                        memoryStream.Seek(0, SeekOrigin.Begin);
                                        fileStream.CopyTo(memoryStream);
                                        formdata = string.Format(fileFormdataTemplate, file.Key, Path.GetFileName(fileNameOrFileData));
                                        fileStream.Dispose();
                                    }
                                    else
                                    {
                                        //不存在文件或只是注释
                                        formdata = string.Format(dataFormdataTemplate, file.Key, file.Value);
                                    }
                                }

                                //统一处理
                                var formdataBytes = encoding.GetBytes(postStream.Length == 0 ? formdata.Substring(2, formdata.Length - 2) : formdata);//第一行不需要换行
                                postStream.Write(formdataBytes, 0, formdataBytes.Length);

                                //写入文件
                                if (memoryStream.Length > 0)
                                {
                                    memoryStream.Seek(0, SeekOrigin.Begin);

                                    byte[] buffer = new byte[1024];
                                    int bytesRead = 0;
                                    while ((bytesRead = memoryStream.Read(buffer, 0, buffer.Length)) != 0)
                                    {
                                        postStream.Write(buffer, 0, bytesRead);
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }
                    //结尾
                    var footer = encoding.GetBytes("\r\n--" + boundary + "--\r\n");
                    postStream.Write(footer, 0, footer.Length);

                    contentType = string.Format("multipart/form-data; boundary={0}", boundary);
                }
                #endregion

                request.ContentType = contentType;

                #region 输入二进制流
                if (postStream != null && postStream.Length > 0)
                {
                    //直接写入流
                    using (Stream requestStream = request.GetRequestStream())
                    {
                        byte[] buffer = new byte[postStream.Length];
                        postStream.Read(buffer, 0, buffer.Length);
                        // 设置当前流的位置为流的开始 
                        postStream.Seek(0, SeekOrigin.Begin);

                        requestStream.Write(buffer, 0, buffer.Length);
                    }
                    postStream.Close();//关闭文件访问
                }
                #endregion

                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                {
                    using (Stream stream = resp.GetResponseStream())
                    {
                        //获取响应内容
                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            result = reader.ReadToEnd();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                var error = ex.ToString();
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        /// <summary>
        /// Put推送文件流
        /// </summary>
        /// <param name="url"></param>
        /// <param name="fileData"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        public static bool HttpPut(string url, byte[] fileData, Dictionary<string, string> header = null)
        {
            bool result = false;
            HttpWebRequest request = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                // 设置HTTP方法为PUT
                request.Method = "PUT";
                // 设置内容类型为二进制流
                request.ContentType = "application/octet-stream";

                #region header
                if (header != null && header.Count != 0)
                {
                    foreach (var item in header)
                    {
                        request.Headers.Add(item.Key, item.Value);
                    }
                }
                #endregion

                // 发送请求并获取响应流
                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(fileData, 0, fileData.Length);
                }
                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                {
                    if (resp.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine("文件上传成功");
                    }
                    else
                    {
                        Console.WriteLine("文件上传失败，状态码：" + resp.StatusCode);
                    }
                }
            }
            catch (Exception ex)
            {
                var error = ex.ToString();
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        /// <summary>
        /// 顺丰调用api接口统一返回数据
        /// </summary>
        /// <param name="environment">调用环境，bspgw：生产环境；sfapi-hk：香港生产环境；sfapi-sbox：沙箱环境</param>
        /// <returns></returns>
        public static string GetResponseString(Dictionary<string, string> content, Dictionary<string, string> header = null, string environment = "bspgw")
        {
            return HttpPost(sfapi_url, content, header, environment);
        }

        /// <summary>
        /// 顺丰调用api接口统一返回数据
        /// </summary>
        /// <param name="header"></param>
        /// <param name="environment">调用环境，bspgw：生产环境；sfapi-hk：香港生产环境；sfapi-sbox：沙箱环境</param>
        /// <returns></returns>
        public static SFResponseApiResultData GetResponseApiResultData(Dictionary<string, string> content, Dictionary<string, string> header = null, string environment = "bspgw")
        {
            SFResponseApiResultData data = null;
            var result = GetResponseString(content, header, environment);
            if (!string.IsNullOrEmpty(result))
            {
                data = JsonHelper.DeserializeObject<SFResponseApiResultData>(result);
            }
            return data;
        }

        /// <summary>
        /// 顺丰调用AccessToken接口统一返回数据
        /// </summary>
        /// <param name="environment">调用环境，sfapi：生产环境；sfapi-sbox：沙箱环境</param>
        /// <returns></returns>
        public static SFResponseAccessToken GetResponseAccessToken(Dictionary<string, string> content, string environment = "sfapi")
        {
            SFResponseAccessToken data = null;
            var result = GetResponseString(content, environment);
            if (!string.IsNullOrEmpty(result))
            {
                data = JsonHelper.DeserializeObject<SFResponseAccessToken>(result);
            }
            return data;
        }

        /// <summary>
        /// 顺丰调用FOP接口返回数据
        /// </summary>
        /// <returns></returns>
        public static SFResponseFop GetResponseFop(string postData, Dictionary<string, string> fileDictionary)
        {
            SFResponseFop data = null;
            var result = HttpFile(sfapi_url, postData, fileDictionary);
            if (!string.IsNullOrEmpty(result))
            {
                data = JsonHelper.DeserializeObject<SFResponseFop>(result);
            }
            return data;
        }

        /// <summary>
        /// 顺丰调用WP接口返回数据（用于通过临时地址上传文件）
        /// </summary>
        /// <param name="url"></param>
        /// <param name="postData"></param>
        /// <param name="fileDictionary"></param>
        /// <returns></returns>
        public static string GetResponseWp(string url, string postData, Dictionary<string, string> fileDictionary)
        {
            return HttpFile(url, postData, fileDictionary);
        }

        /// <summary>
        /// 顺丰调用FIS接口返回数据
        /// </summary>
        /// <param name="postData"></param>
        /// <param name="fileDictionary"></param>
        /// <param name="isFormalEnvironment">是否正式环境，默认为true 正式环境，否则测试环境</param>
        /// <returns></returns>
        public static SFResponseFis GetResponseFis(string postData, Dictionary<string, string> fileDictionary, bool isFormalEnvironment = true)
        {
            SFResponseFis data = null;
            string url = isFormalEnvironment ? sfapi_url_fis : sfapi_url_fis_sit;
            var result = HttpFile(url, postData, fileDictionary);
            if (!string.IsNullOrEmpty(result))
            {
                data = JsonHelper.DeserializeObject<SFResponseFis>(result);
            }
            return data;
        }

        /// <summary>
        /// 顺丰调用FIS接口返回数据
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static SFResponseApiResultData GetResponseSit(Dictionary<string, string> content)
        {
            SFResponseApiResultData data = null;
            var result = HttpPost(sfapi_url_sit, content);
            if (!string.IsNullOrEmpty(result))
            {
                data = JsonHelper.DeserializeObject<SFResponseApiResultData>(result);
            }
            return data;
        }

        /// <summary>
        /// 顺丰调用 Sgspdcs 接口统一返回数据
        /// </summary>
        /// <param name="header"></param>
        /// <param name="environment">调用环境，sfapi：生产环境；sfapi-sbox：沙箱环境</param>
        /// <returns></returns>
        public static string GetResponseSgspdcsString(Dictionary<string, string> content, Dictionary<string, string> header = null, string environment = "sfapi")
        {
            return HttpPost(sfapi_url_sgspdcs, content, header, environment);
        }

        /// <summary>
        /// 顺丰调用 Sgspdcs 接口统一返回数据
        /// </summary>
        /// <param name="header"></param>
        /// <param name="environment">调用环境，sfapi：生产环境；sfapi-sbox：沙箱环境</param>
        /// <returns></returns>
        public static SFResponseApiResultData GetResponseSgspdcs(Dictionary<string, string> content, Dictionary<string, string> header = null, string environment = "sfapi")
        {
            SFResponseApiResultData data = null;
            var result = GetResponseSgspdcsString(content, header, environment);
            if (!string.IsNullOrEmpty(result))
            {
                data = JsonHelper.DeserializeObject<SFResponseApiResultData>(result);
            }
            return data;
        }
        
    }
}
